package main

import (
	"encoding/json"
	"fmt"
	"github.com/martini-contrib/render"
	"html/template"
	"io/ioutil"
	"math/rand"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

func home(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.Redirect("/login")
	} else {
		user := model.session.Get("user").(UserInfo)
		page := PageData{Title: "任务列表", Body: map[string]interface{}{"user": user, "data": jobMap}}
		model.r.HTML(200, "index", page)
	}
}
func login(model RequestModel) {
	if model.request.Method == "POST" {
		error := model.request.ParseForm()
		if error == nil {

			code := model.session.Get("code").(string)
			usr := model.request.Form.Get("usr")
			code1 := model.request.Form.Get("code")
			pwd := model.request.Form.Get("pwd")
			if debug {
				fmt.Println("Post data is   ", code, code1, usr, pwd)
			}
			if code1 == code && len(usr) > 0 && len(pwd) > 0 {
				user, ok := userMap[usr]
				if ok && user.Password == pwd {
					model.session.Set("user", user)
					model.r.Redirect("/")
				} else {
					model.r.Error(403)
				}
			} else {
				model.r.Error(401)
			}

		} else {
			if debug {
				fmt.Println("find error:", error)
			}
			model.r.Error(500)
		}
	} else {
		verify, code := getVerifyCode()
		model.session.Set("verify", verify)
		model.session.Set("code", code)
		model.r.HTML(200, "login", PageData{Title: "hello worlds", Body: map[string]interface{}{"verify": verify}}, render.HTMLOptions{})
	}

}
func logout(model RequestModel) {
	if model.session.Get("user") != nil {
		model.session.Clear()
	}
	model.r.Redirect("/login")
}
func getVerifyCode() (string, string) {
	s := rand.NewSource(time.Now().Unix())
	r := rand.New(s)
	t := r.Intn(2)
	a := r.Intn(9) + 1
	b := r.Intn(9) + 1
	var c int
	switch t {
	case 0:
		c = a + b
		return strconv.Itoa(a) + "+" + strconv.Itoa(b) + "=?", strconv.Itoa(c)
	case 1:
		if a < b {
			m := a
			a = b
			b = m
		}
		c = a - b
		return strconv.Itoa(a) + "-" + strconv.Itoa(b) + "=?", strconv.Itoa(c)
	}
	c = a + b
	return strconv.Itoa(a) + "+" + strconv.Itoa(b) + "=?", strconv.Itoa(c)
}
func userList(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.Redirect("/login")
	} else {
		user := model.session.Get("user").(UserInfo)
		if debug {
			fmt.Println("map length is ", len(userMap))
		}
		page := PageData{Title: "用户列表", Body: map[string]interface{}{"user": user, "data": userMap}}
		model.r.HTML(200, "userList", page)
	}
}
func deleteUser(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid user"})
	} else {
		user := model.session.Get("user").(UserInfo)
		rst, er := regexp.MatchString(user.Permissions, "ADMIN")
		if rst && er == nil {
			name, ok := model.params["name"]
			if ok {
				delete(userMap, name)
				errs := saveUserInfo()
				if errs != nil {
					model.r.JSON(200, CodeMsg{Code: -1, Msg: "error when save data"})
				} else {
					model.r.JSON(200, CodeMsg{Code: 0, Msg: "操作成功"})
				}
			} else {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid user"})
			}
		} else {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid permission"})
		}
	}
}
func configInfo(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.Redirect("/login")
	} else {
		var data string
		user := model.session.Get("user").(UserInfo)
		f, ers := os.Open(configFile)
		defer func() {
			f.Close()
			model.r.HTML(200, "config", PageData{Title: "配置信息", Body: map[string]interface{}{"user": user, "data": template.HTML(data)}})
		}()
		rs, _ := regexp.MatchString(user.Permissions, "ADMIN")
		if !rs {
			data = "permission denied!"
			return
		}

		if ers != nil {
			data = "open file error"
			return
		}
		body, er := ioutil.ReadAll(f)
		if er != nil {
			data = "read file error"
			return
		}
		data = string(body)
		data = strings.Replace(data, "\r\n", `<br/>`, -1)
		data = strings.Replace(data, "\r", `<br/>`, -1)
		data = strings.Replace(data, "\n", `<br/>`, -1)
	}
}
func checkJobName(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.JSON(200, CodeMsg{Code: -1, Msg: "非法的用户"})
	} else {
		var data map[string]interface{}
		body, er := ioutil.ReadAll(model.request.Body)
		if er != nil {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "读取数据是出错"})
			return
		}
		json.Unmarshal(body, &data)
		name, ok := data["name"].(string)
		if !ok {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "数据类型错误"})
			return
		}
		_, oks := jobMap[name]
		if !oks {
			model.r.JSON(200, CodeMsg{Code: 0, Msg: "名称可用"})
			return
		}
		model.r.JSON(200, CodeMsg{Code: -1, Msg: "名称已经占用，请重试！"})
	}
}
func logInfo(model RequestModel) {
	if model.session.Get("user") == nil {
		if model.request.Method == "POST" {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid user"})
		} else {
			model.r.Redirect("/login")
		}
	} else {
		if model.request.Method == "POST" {
			body, er := ioutil.ReadAll(model.request.Body)
			if er != nil {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid user"})
				return
			}
			var log LogModel
			json.Unmarshal(body, &log)
			if log.Name == "" {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid log Name"})
				return
			}
			var file *os.File
			var filename string
			if log.Name == "defaults" {
				filename = logs
			} else {
				job, ok := jobMap[log.Name]
				if !ok {
					model.r.JSON(200, CodeMsg{Code: -1, Msg: "can't find log file"})
					return
				}
				if log.Type == "run" {
					filename = job.RunLog
				} else {
					filename = job.HookLog
				}

			}
			lf, er := os.Open(filename)
			if er != nil {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "error when read log:" + er.Error()})
				return
			}
			file = lf
			file.Seek(log.Start, 0)
			bb := make([]byte, 1024)
			n, er := file.Read(bb)
			if er != nil {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "error when read log info:" + er.Error()})
				return
			}
			data := string(bb[0:n])
			data = strings.Replace(data, "\r\n", `<br/>`, -1)
			data = strings.Replace(data, "\r", `<br/>`, -1)
			data = strings.Replace(data, "\n", `<br/>`, -1)
			log.Data = template.HTML(data)
			log.Length = n
			model.r.JSON(200, CodeMsg{Code: 0, Msg: "操作成功", Data: log})

		} else {
			page := getDefaltPageData("日志信息", model)
			typs, ok := model.params["type"]
			name, ok := model.params["name"]
			if !ok {
				name = "defaults"
			}
			page.put("logName", name)
			page.put("logType", typs)
			model.r.HTML(200, "logInfo", page)
		}
	}
}
func userInfo(model RequestModel) {
	if model.session.Get("user") == nil {
		if model.request.Method == "POST" {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid user"})
		} else {
			model.r.Redirect("/login")
		}
	} else {
		if model.request.Method == "POST" {
			body, er := ioutil.ReadAll(model.request.Body)
			defer model.request.Body.Close()
			if er != nil {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid data"})
				return
			}
			var user UserInfo
			ers := json.Unmarshal(body, &user)
			if ers != nil {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "error when unmarshal data:" + string(body)})
				return
			}
			userMap[user.UserName] = user
			ers = saveUserInfo()
			if ers != nil {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "inner error when write file"})
				return
			}
			model.r.JSON(200, CodeMsg{Code: 0, Msg: "操作成功"})

		} else {
			name := model.params["name"]
			user, ok := userMap[name]
			if ok {
				model.r.HTML(200, "userInfo", PageData{Title: "用户[" + user.UserName + "]的详情", Body: map[string]interface{}{"data": user, "type": 1}}, render.HTMLOptions{""})
			} else {
				model.r.HTML(200, "userInfo", PageData{Title: "新建用户", Body: map[string]interface{}{"type": 0}}, render.HTMLOptions{""})
			}
		}
	}

}
func deleteJob(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid user"})
	} else {
		user := model.session.Get("user").(UserInfo)
		rst, er := regexp.MatchString(user.Permissions, "ADMIN|MANAGER")
		if rst && er == nil {
			name, ok := model.params["name"]
			if ok {
				delete(jobMap, name)
				errs := saveJobInfo()
				if errs != nil {
					model.r.JSON(200, CodeMsg{Code: -1, Msg: "error when save data"})
				} else {
					model.r.JSON(200, CodeMsg{Code: 0, Msg: "操作成功"})
				}
			} else {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid user"})
			}
		} else {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid permission"})
		}
	}
}
func jobInfo(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.Redirect("/login")
	} else {
		if model.request.Method == "POST" {
			body, er := ioutil.ReadAll(model.request.Body)
			defer model.request.Body.Close()
			if er != nil {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "inner error：can't read data" + er.Error()})
				return
			}
			var job JobInfo
			ers := json.Unmarshal(body, &job)
			if ers != nil {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "inner error:can't unmarshal data" + ers.Error()})
				return
			}
			jobOld, ok := jobMap[job.Name]
			if ok {
				jobOld.HookLog = job.HookLog
				jobOld.RunLog = job.RunLog
				jobOld.RunCmd = job.RunCmd
				jobOld.RunCmdExt = job.RunCmdExt
				jobOld.HookCmd = job.HookCmd
				jobOld.HookCmdExt = job.HookCmdExt
				job.RunStatus = jobOld.RunStatus

			}
			if debug {
				fmt.Println(jobOld, job)
			}
			jobMap[job.Name] = job
			ers = saveJobInfo()
			if ers != nil {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "inner error when write file"})
				return
			}
			model.r.JSON(200, CodeMsg{Code: 0, Msg: "操作成功"})

		} else {
			name := model.params["name"]
			job, ok := jobMap[name]
			if ok {
				model.r.HTML(200, "jobInfo", PageData{Title: "任务[" + job.Name + "]的详情", Body: map[string]interface{}{"data": job, "type": 1}}, render.HTMLOptions{""})
			} else {
				model.r.HTML(200, "jobInfo", PageData{Title: "新建任务", Body: map[string]interface{}{"type": 0}}, render.HTMLOptions{""})
			}
		}
	}

}
func saveUserInfo() error {
	var userArrays []UserInfo
	for _, v := range userMap {
		userArrays = append(userArrays, v)
	}
	bb, er := json.MarshalIndent(userArrays, "", "    ")
	if er != nil {
		return er
	}
	return writeFileWithTrunc(bb, users)
}
func saveJobInfo() error {
	var jobarrays []JobInfo
	for _, v := range jobMap {
		jobarrays = append(jobarrays, v)
	}
	bb, er := json.MarshalIndent(jobarrays, "", "    ")
	if er != nil {
		return er
	}
	return writeFileWithTrunc(bb, jobs)

}
func stopJobInfo(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.JSON(200, CodeMsg{Code: -1, Msg: "无效的用户信息"})
	} else {
		user := model.session.Get("user").(UserInfo)
		if getPermissionCode(user.Permissions) < 1 {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "用户权限不足"})
			return
		}
		name := model.params["name"]
		stopJobByName(name)
		model.r.JSON(200, CodeMsg{Code: 0, Msg: "操作成功"})
	}

}
func storeLog(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.JSON(200, CodeMsg{Code: -1, Msg: "无效的用户信息"})
	} else {
		body, er := ioutil.ReadAll(model.request.Body)
		if er != nil {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid user"})
			return
		}
		var log LogModel
		json.Unmarshal(body, &log)
		if log.Name == "" {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "invalid log Name"})
			return
		}
		var filename string
		var file *os.File
		if log.Name == "defaults" {
			filename = logs
			file = logFile
		} else {
			job, ok := jobMap[log.Name]
			if !ok {
				model.r.JSON(200, CodeMsg{Code: -1, Msg: "can't find log file"})
				return
			}
			if log.Type == "run" {
				filename = job.RunLog
				file = job.RunLogFile
			} else {
				filename = job.HookLog
				file = job.HookLogFile
			}

		}
		if log.Length > 0 {
			reStoreFile(filename, file, log.Length)
		}
		model.r.JSON(200, CodeMsg{Code: 0, Msg: "存储完成"})
	}
}
func startJobInfo(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.JSON(200, CodeMsg{Code: -1, Msg: "无效的用户信息"})
	} else {
		user := model.session.Get("user").(UserInfo)
		if getPermissionCode(user.Permissions) < 1 {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "用户权限不足"})
			return
		}
		name := model.params["name"]
		startJobByName(name)
		model.r.JSON(200, CodeMsg{Code: 0, Msg: "操作成功"})
	}
}
func buildJobInfo(model RequestModel) {
	if model.session.Get("user") == nil {
		model.r.JSON(200, CodeMsg{Code: -1, Msg: "无效的用户信息"})
	} else {
		user := model.session.Get("user").(UserInfo)
		if getPermissionCode(user.Permissions) < 1 {
			model.r.JSON(200, CodeMsg{Code: -1, Msg: "用户权限不足"})
			return
		}
		startHookJob(model)
	}
}
func startHookJob(model RequestModel) {
	name := model.params["name"]
	startJobHookByName(name)
	model.r.JSON(200, CodeMsg{Code: 0, Msg: "操作成功"})
}
func writeFileWithTrunc(data []byte, file string) error {
	f, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC|os.O_CREATE|os.O_SYNC, os.ModePerm)
	defer f.Close()
	if err != nil {
		return err
	}
	_, ers := f.Write(data)
	f.Sync()
	return ers
}
func getPermissionCode(permission string) int {
	rgx, er := regexp.Compile(permission)
	if er != nil {
		return -1
	}
	if rgx.MatchString("ADMIN") {
		return 4
	}
	if rgx.MatchString("MANAGER") {
		return 3
	}
	if rgx.MatchString("ST") {
		return 2
	}
	if rgx.MatchString("LOGGER") {
		return 1
	}
	return 0
}
func translatePermission(permission string) string {
	permission = strings.Replace(permission, "ADMIN", "超级管理", -1)
	permission = strings.Replace(permission, "MANAGER", "任务管理", -1)
	permission = strings.Replace(permission, "ST", "任务起停", -1)
	permission = strings.Replace(permission, "LOGGER", "日志查看", -1)
	return permission
}
